﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Taobao.Tools2.Domain;
using Taobao.Common;
using Taobao.Tools2.Domain.EntityFramework;
using System.Threading;
using Taobao.Top.Api.Request;
using System.Transactions;
using System.Windows.Forms;

namespace Taobao.Tools2
{
    public class TaobaoToolsProcesser : Taobao.Common.TaobaoProcessor<Shop>
    {
        #region Const & Static

        private static List<string[]> toUpdateTradeStatus = new List<string[]>() {
             new string[]{"WAIT_BUYER_PAY","等待买家付款的订单"},
             new string[]{"TRADE_NO_CREATE_PAY","等待支付宝创建付款的订单"},
             new string[]{"WAIT_SELLER_SEND_GOODS","等待卖家发货的订单"}
        };

        protected const string Delivery_WaitSend = "待发货";
        protected const string Delivery_Success = "发货成功";
        protected readonly int DefaultBeforeMinutesOfUpdateByIncreament = Int32.Parse(System.Configuration.ConfigurationManager.AppSettings["BeforeMinutesOfUpdateByIncreament"]??"30");
        //protected readonly bool EnableUpdateSubOrderInfos = false;
        protected readonly bool GatherEndTimeAndFullInfo = System.Configuration.ConfigurationManager.AppSettings["UpdateEndTimeAndFullInfo"] == "true";
        protected const string FenXiaoType = "fenxiao";
        #endregion

        #region Ctor
        public TaobaoToolsProcesser(string requestUrl, string moduleName, Shop shop)
            : base(requestUrl, moduleName, shop)
        { 
        }

        public TaobaoToolsProcesser(string requestUrl,string moduleName,short shopID)
            :base(requestUrl,moduleName,shopID)
        {
        }

        public TaobaoToolsProcesser(string requestUrl, string moduleName, short shopID, IOutputWriter textWriter)
            : base(requestUrl, moduleName, shopID, textWriter)
        {
        }
        #endregion

        #region Properties
        protected IRepository<Shop,short> ShopRepository { get; set; }
        protected IRepository<Distributor,int> DistributorRepository { get; set; }
        protected IRepository<Log,long> LogRepository { get; set; }
        protected IRepository<OrderInfo,long> OrderInfoRepository { get; set; }
        protected IRepository<OutSent,long> OutSentRepository { get; set; }
        protected IRepository<OutSentNum,int> OutSentNumRepository { get; set; }
        protected IRepository<Refund,long> RefundRepository { get; set; }
        protected IRepository<Trade, long> TradeRepository { get; set; }
        protected IRepository<PromotionDetail, long> PromotionDetailRepository { get; set; }
        protected IRepository<Sender, short> SenderRepository { get; set; }
        protected IRepository<Item, long> ItemRepository { get; set; }
        #endregion

        #region Init
        private EfDbContext context;
        protected override void Initialize()
        {
           if (context != null)
           {
               context.Dispose();
           }
           context = new EfDbContext();
           
           ShopRepository = new EntityRepository<Shop, short>(context);
           DistributorRepository = new EntityRepository<Distributor, int>(context);
           LogRepository = new EntityRepository<Log,long>(context);
           OrderInfoRepository = new EntityRepository<OrderInfo,long>(context);
           OutSentRepository = new EntityRepository<OutSent,long>(context);
           OutSentNumRepository = new EntityRepository<OutSentNum,int>(context);
           RefundRepository = new EntityRepository<Refund,long>(context);
           TradeRepository = new EntityRepository<Trade,long>(context);
           PromotionDetailRepository = new EntityRepository<PromotionDetail, long>(context);
           SenderRepository = new EntityRepository<Sender, short>(context);
           Logger = new Logger(LogRepository);
           ItemRepository = new EntityRepository<Item, long>(context);
        }
        #endregion

        #region Abstract
        protected override Shop GetShop(short shopID)
        {
            return ShopRepository.FindAll().AsQueryable().FirstOrDefault(s => s.ID.Equals(shopID));
        }
        #endregion

        #region Override Methods
         
        protected override void DoExcuteJob()
        {
            string msg = "starting";
            try
            {
                var usingIncreaement = ToolConfiguration.Current.UseIncrement;

                OnProcessStarted();

                var result = AuthorizationProvider.Current.Authorize(Shop.Name);
                if (result == null || !result.Status.Equals("yes", StringComparison.OrdinalIgnoreCase))
                {
                    throw new Exception(result == null ? "店铺未经授权" : result.Info);
                }

                GetItems();

                if (ToolConfiguration.Current.PreparingOperation)
                {
                    PrepareDelivery();
                }

                if (ToolConfiguration.Current.SentBeforeAllAction)
                {
                    SendDeliveries();
                }

                if (ToolConfiguration.Current.GetRefunds)
                {
                    GetRefunds(usingIncreaement);
                }
                if (ToolConfiguration.Current.GetTrades)
                {
                    GetTrades(usingIncreaement);    //GetTrades
                }
                if (ToolConfiguration.Current.GetTradesInfo)
                {
                    //GetTradesInfo();  // GetTradesInfo
                }
                if (ToolConfiguration.Current.UpdateTradesInfo)
                {
                    UpdateTradesInfoAndEndTime();
                }
                if (ToolConfiguration.Current.Sent)
                {
                    SendDeliveries();
                }
                OnProcessCompleted();
                msg = "completed";
            }
            catch (Exception e)
            {
                HandleException("程序运行中出错:"+e.Message, e);
            }
            finally
            {
                try
                {
                    Thread.Sleep(ThreadSleepTick);
                    OutputWriter.Clear();
                    
                    Thread.Sleep(ThreadSleepTick);

                    if (msg == "completed")
                    {
                        if (SwitchShop != null)
                        {
                            var sp = SwitchShop(Shop);
                            var newShop = ShopRepository.FindAll().AsQueryable().Where(s=>s.ID==sp).FirstOrDefault();
                            if (newShop != null)
                                ShopID = newShop.ID;
                        }

                        var interval = ToolConfiguration.Current.ProcessInterval * 60;
                        var hours = ToolConfiguration.Current.ProcessInterval / 60;
                        var minutes = ToolConfiguration.Current.ProcessInterval % 60;
                        var seconds = 0;
                        while (interval-- > 0 && msg == "completed")
                        {
                            hours = interval / (60 * 60);
                            minutes = (interval % (60 * 60)) / 60;
                            seconds = interval % 60;
                            TimeSpan timeSpan = new TimeSpan(hours, minutes, seconds);
                            ExcuteUpdateStatus("程序将在:" + timeSpan.ToString() + " 后重新自动执行。");
                            Thread.Sleep(1000);
                        }
                    }
                }
                catch (Exception error)
                {
                    HandleException("程序重新运行中出错。", error);
                    ExcuteUpdateStatus("程序将重新自动执行。");
                }
                finally
                {
                    Initialize();
                    DoExcuteJob();
                }
            }
        }


                 
        #endregion

        #region Detail Tasks

        #region Get End Time

        private void GetEndTime()
        {
            try
            {
                var endTime = DateTime.Parse("1990.01.01");
                var allTradesNeedUpdateEndTime = TradeRepository.FindAll().AsQueryable()
                                                                .Where(t => t.EndTime == null || t.EndTime.Value == endTime)
                                                                .Where(t=>t.ShopID == ShopID)
                                                                .OrderBy(t=>t.ID);
                var title = string.Format("需要更新EndTime的订单");
                //var totalCount = allTradesNeedUpdateEndTime.Count();
                //UpdateTask(title, totalCount, () =>
                //{
                //    return ProcessQueryable<Trade>(title, DefaultPageSize, (pageSize, pageNo) => 
                //    {
                //        return allTradesNeedUpdateEndTime.Skip(pageSize * (pageNo - 1)).Take(pageSize).ToList();
                //    },
                //    UpdateTradeFullInfo, totalCount);
                //});
                UpdateTradesInternal(allTradesNeedUpdateEndTime, title);
            }
            catch (Exception e)
            {
                HandleException("获得需要更新EndTime的订单失败", e);
            }
        }

        private void UpdateTradesInternal(IQueryable<Trade> trades, string title)
        {
            long success = 0;
            var pageSize = DefaultPageSize;
            var totalCount = trades.Count();
            ExcuteUpdateStatus(string.Format("开始更新{0}:{1}条", title, totalCount));
            try
            {
                OutputWriter.WriteLine(string.Format("开始更新所有{0}...", title), OutputFormatType.Title); 
                LogStatisticsStart(title, totalCount);
                try
                {
                    var pageCount = (int)(totalCount / pageSize) + ((totalCount % pageSize > 0) ? 1 : 0);
                    OutputWriter.WriteLine("将要获取的" + title + "的总页数为:" + pageCount + "页，每页:" + pageSize + "条。", OutputFormatType.Title);
                    var currentPageNo = 1;
                    var index = 0;
                    var currentContentList = trades.Skip(pageSize * (currentPageNo - 1)).Take(pageSize).ToList();
                    do
                    {
                        try
                        {
                            OutputWriter.WriteLine("第" + currentPageNo + "页：", OutputFormatType.Title);
                            index = 0;
                            foreach (var t in currentContentList)
                            {
                                index++;
                                if (UpdateTradeFullInfo(t, (currentPageNo - 1) * pageSize + index))
                                    success++;
                            }
                        }
                        catch (Exception e)
                        {
                            HandleException("更新第" + currentPageNo + "页的" + title + "失败。", e);
                            Thread.Sleep(1000);
                        }
                        currentPageNo++;

                        try
                        {
                            currentContentList = trades.Skip(pageSize * (currentPageNo - 1)).Take(pageSize).ToList();
                        }
                        catch (Exception ep)
                        {
                            continue;
                        }
                    } while (currentPageNo <= pageCount);
                }
                catch (Exception e)
                {
                    HandleException("处理查询数据分页出错", e);
                }
            }
            catch (Exception e)
            {
            }
            finally
            {
                LogStatisticsEnd(title, totalCount, success);
            }
        }
        #endregion

        #region Get Trades Info (No Implement)
        private void GetTradesInfo()
        {
        }
        #endregion

        #region Update Trades Info

        private void UpdateTradesInfoAndEndTime()
        {
            var needUpdate = false;
            var updatedInSchedules = false;
            var updatedStartDateTime = DateTime.Now;
            var shop = ShopRepository.FindByID(Shop.ID);
            // The Count will be correct always.
            if (shop.IsUpdateDetailScheduled != null && shop.IsUpdateDetailScheduled.Value == true)
            {
                if (shop.ScheduledUpdateTime != null && shop.ScheduledUpdateCountEachDay != null && shop.ScheduledUpdateCountEachDay.Value > 0)
                {
                    if (shop.LastUpdatedDetailTime != null && shop.LastUpdatedDetailTime.Value.Date < updatedStartDateTime.Date)
                    {
                        try
                        {
                            shop.ScheduledUpdateCountToday = 0;
                            ShopRepository.Update(shop);
                        }
                        catch(Exception e)
                        {
                            HandleException("Update ScheduledUpdateCountToday Failed!", e);
                        }
                    }

                    if (((updatedStartDateTime.TimeOfDay >= shop.ScheduledUpdateTime.Value.TimeOfDay))
                        && (shop.ScheduledUpdateCountToday == null || shop.ScheduledUpdateCountToday.Value < shop.ScheduledUpdateCountEachDay.Value))
                    {
                        needUpdate = true;
                        updatedInSchedules = true;
                    }
                }
            }
            else
            {
#if DEBUG
                needUpdate = false;
#else
                needUpdate =true;
#endif
            }
            
            if (needUpdate)
            {
                if (GatherEndTimeAndFullInfo)
                {
                    UpdateTradesInfoAll();
                }
                else
                {
                    GetEndTime();
                    UpdateTradesInfo();
                }

                try
                {
                    shop = ShopRepository.FindByID(Shop.ID);
                    // Update Shop Information
                    if (updatedInSchedules)
                    {
                        var updatedEndDateTime = DateTime.Now;
                        if (updatedEndDateTime.Date != updatedStartDateTime.Date)
                        {
                            shop.ScheduledUpdateCountToday = 0;
                        }
                        else
                        {
                            shop.ScheduledUpdateCountToday = shop.ScheduledUpdateCountToday == null ? 1 : shop.ScheduledUpdateCountToday.Value + 1;
                        }
                        shop.LastUpdatedDetailTime = updatedEndDateTime;
                        ShopRepository.Update(shop);
                    }
                }
                catch (Exception e)
                {
                    HandleException("Update LastUpdatedDetailTime Failed!", e);
                }
            }
        }

        private void UpdateTradesInfo()
        {
            foreach (var status in GetUpdateTradeStatus())
            {
                UpdateTradesInfoNormal(status);
            }
        }

        private void UpdateTradesInfoNormal(string[] status)
        {
            try
            {
                var statusInfo = status[0];
                var allTradesNeedToBeUpdated = TradeRepository.FindAll().AsQueryable()
                                                              .Where(t => t.Status.Equals(statusInfo, StringComparison.OrdinalIgnoreCase))
                                                              .Where(t=>t.ShopID ==ShopID)
                                                              .OrderBy(t => t.ID);

                var title = string.Format("{0}", status[1]);
                //var totalCount = allTradesNeedToBeUpdated.Count();
                //UpdateTask(title, totalCount, () =>
                //{
                //    return ProcessQueryable<Trade>(title, DefaultPageSize, (pageSize, pageNo) =>
                //    {
                //        return allTradesNeedToBeUpdated.Skip(pageSize * (pageNo - 1)).Take(pageSize).ToList();
                //    },
                //    UpdateTradeFullInfo, totalCount);
                //});
                UpdateTradesInternal(allTradesNeedToBeUpdated, title);
            }
            catch (Exception e)
            {
                HandleException(string.Format("获取需要更新的{0}订单信息失败", status[1]), e);
            }
        }

        private bool UpdateTradeFullInfo(Trade trade,long index)
        {
            var result = false;
            try
            {
                //using (var scope = new TransactionScope())
                {
                    //var  newtrade = TradeRepository.FindAll().AsQueryable().Single(t => t.ID == trade.ID);
                    var request = new TradeFullinfoGetRequest();
                    if (ToolConfiguration.Current.EnableUpdateTradeDetail)
                    {
                        request.Fields = "num_iid,seller_nick,end_time, buyer_nick, title, type, created, sid, tid,  status, payment, discount_fee, adjust_fee, post_fee, total_fee, pay_time, buyer_memo, seller_memo, alipay_no, buyer_message,  iid, num, price, buyer_alipay_no, receiver_name, receiver_state, receiver_city, receiver_district, receiver_address, receiver_zip, receiver_mobile, receiver_phone, buyer_email, shipping_type, trade_memo, is_3D ,orders,promotion_details";//.title, orders.price,orders.oid, orders.num, orders.iid,  orders.status, orders.tid, orders.total_fee, orders.payment, orders.discount_fee, orders.adjust_fee, orders.timeout_action_time,orders.sku_properties_name, orders.item_meal_name, item_memo ";                                
                    }
                    else
                    {
                        request.Fields = "num_iid,seller_nick,end_time, buyer_nick, title, type, created, sid, tid,  status, payment, discount_fee, adjust_fee, post_fee, total_fee, pay_time, buyer_memo, seller_memo, alipay_no, buyer_message,  iid, num, price, buyer_alipay_no, receiver_name, receiver_state, receiver_city, receiver_district, receiver_address, receiver_zip, receiver_mobile, receiver_phone, buyer_email, shipping_type, trade_memo, is_3D ";
                    }
                    request.Tid = trade.TaobaoTID;
                    var tTrade = Client.TradeFullinfoGet(request, SessionKey);

                    trade.ShopID = ShopID;
                    trade.ReceiverAddress = tTrade.ReceiverAddress;
                    trade.ReceiverCity = tTrade.ReceiverCity;
                    trade.ReceiverDistrict = tTrade.ReceiverDistrict;
                    trade.ReceiverMobile = tTrade.ReceiverMobile;
                    trade.ReceiverName = tTrade.ReceiverName;
                    trade.ReceiverPhone = tTrade.ReceiverPhone;
                    trade.ReceiverState = tTrade.ReceiverState;
                    trade.ReceiverZip = tTrade.ReceiverZip;
                    trade.SellerName = tTrade.SellerName;
                    trade.SellerMobile = tTrade.SellerMobile;
                    trade.BuyerAlipayNo = tTrade.BuyerAlipayNo;
                    trade.PostFee = tTrade.PostFee;
                    trade.ShippingType = tTrade.ShippingType;
                    trade.Type = tTrade.Type;
                    trade.Payment = tTrade.Payment;
                    if (!string.IsNullOrEmpty(tTrade.PayTime))
                    {
                        trade.PayTime = Util.ChangeType<DateTime>(tTrade.PayTime, DateTime.MinValue);
                    }
                    if (tTrade.EndTime != null)
                    {
                        trade.EndTime = Util.ChangeType<DateTime>(tTrade.EndTime, DateTime.MinValue);
                    }
                    if (trade.TProcess <= 0)
                    {
                        if (tTrade.Status == "WAIT_SELLER_SEND_GOODS")
                        {
                            if (trade.TProcess < 0)
                            {
                                trade.TProcess = 0;
                            }
                        }
                        else if (tTrade.Status == "WAIT_BUYER_PAY")
                        {
                            trade.TProcess = -1;
                        }
                        else if (tTrade.Status == "TRADE_NO_CREATE_PAY")
                        {
                            trade.TProcess = -2;
                        }
                    }
                    trade.Status = tTrade.Status;
                    trade.SellerNick = tTrade.SellerNick;
                    trade.BuyerNick = tTrade.BuyerNick;
                    trade.BuyerMemo = "买家备注：" + tTrade.BuyerMemo + "||买家留言：" + tTrade.BuyerMessage;
                    trade.SellerMemo = tTrade.SellerMemo;
                    int sellerFlag = tTrade.SellerFlag;
                    trade.SellerFlag = tTrade.SellerFlag.ToString();
                    trade.AlipayNo = tTrade.AlipayNo;
                    if (tTrade.Orders.Count > 0)
                    {
                        trade.OrdersTitle = tTrade.Orders[0].Title;
                        trade.OrderNum = (short)tTrade.Orders.Count;
                        trade.DiscountFee = tTrade.Orders.Sum<Taobao.Top.Api.Domain.Order>(o => Util.ChangeType<decimal>(o.DiscountFee, 0));
                        trade.AdjustFee = tTrade.Orders.Sum<Taobao.Top.Api.Domain.Order>(o => Util.ChangeType<decimal>(o.AdjustFee, 0));
                        if (trade.OrderInfos == null || trade.OrderInfos.Count != tTrade.Orders.Count || ToolConfiguration.Current.EnableUpdateTradeDetail)
                        {
                            if (trade.OrderInfos != null && trade.OrderInfos.Count > 0)
                            {
                                var allOrderIDs = trade.OrderInfos.Where(c => c.TaobaoOID == null)
                                                                          .Select(c => c.ID).ToList();
                                foreach (var id in allOrderIDs)
                                {
                                    var order = trade.OrderInfos.FirstOrDefault(o => o.ID == id);
                                    if (order != null)
                                    {
                                        OrderInfoRepository.Delete(order);
                                    }
                                }
                            }
                            foreach (Taobao.Top.Api.Domain.Order tOrder in tTrade.Orders)
                            {
                                var order = OrderInfoRepository.FindAll().AsQueryable().Where(o => o.ShopID == ShopID
                                                                                                && o.TradeID == trade.ID
                                                                                                && o.TaobaoOID == tOrder.Oid)
                                                                                       .SingleOrDefault() ?? new OrderInfo();
                                order.NumIID = tOrder.NumIid;
                                order.Title = tOrder.Title;
                                order.TradeID = trade.ID;
                                order.Number = tOrder.Num;
                                order.Price = tOrder.Price;
                                order.IID = tOrder.Iid;
                                order.ItemMealName = tOrder.ItemMealName;
                                order.TaobaoOID = tOrder.Oid;

                                order.AdjustFee = Util.ChangeType<decimal>(tOrder.AdjustFee, 0);
                                order.DiscountFee = Util.ChangeType<decimal>(tOrder.DiscountFee, 0);
                                order.Payment = Util.ChangeType<decimal>(tOrder.Payment, 0);
                                order.RefundID = tOrder.RefundId;
                                if (tOrder.Status != null)
                                {
                                    order.Status = tOrder.Status;
                                }
                                if (tOrder.Modified != null)
                                {
                                    order.Modified = Util.ChangeType<DateTime>(tOrder.Modified, DateTime.MinValue);
                                }
                                //oi.Save();
                                //Item item = GetItemInfo(oi);
                                //oi.SkuPropertiesName = o.SkuPropertiesName;
                                //oi.OuterIId = item.OuterId;
                                //oi.NumIid = item.NumIid;
                                //oi.SkuID = o.SkuId;
                                order.SkuPropertiesName = tOrder.SkuPropertiesName;
                                order.OuterIID = string.IsNullOrEmpty(tOrder.OuterSkuId) ? tOrder.OuterIid : tOrder.OuterSkuId;
                                order.NumIID = tOrder.NumIid;
                                order.SkuID = tOrder.SkuId;
                                order.ShopID = ShopID;
                                OrderInfoRepository.AddOrUpdate(order);
                            }
                        }
                    }

                    if (tTrade.PromotionDetails.Count>0)
                    {
                        if (trade.PromotionDetails == null || trade.PromotionDetails.Count != tTrade.PromotionDetails.Count || ToolConfiguration.Current.EnableUpdateTradeDetail)
                        {
                            foreach (var tDetail in tTrade.PromotionDetails)
                            {
                                var detail = PromotionDetailRepository.FindAll().AsQueryable().Where(p => p.TradeID == trade.ID
                                                                                                       && p.ShopID == ShopID
                                                                                                       && p.PromotionDetailID == tDetail.Id).SingleOrDefault() ?? new PromotionDetail();
                                detail.DiscountFee = Util.ChangeType<decimal>(tDetail.DiscountFee, 0);
                                detail.PromotionDetailID = tDetail.Id;
                                detail.Name = tDetail.PromotionName;
                                detail.ShopID = ShopID;
                                detail.TradeID = trade.ID;
                                PromotionDetailRepository.AddOrUpdate(detail);
                            }
                        }
                    }

                    TradeRepository.Update(trade);

                    if (tTrade.Status != "TRADE_NO_CREATE_PAY" && tTrade.Status != "WAIT_BUYER_PAY")
                    {
                        var outSent = OutSentRepository.FindAll().AsQueryable().Where(o => o.ID == trade.ID).SingleOrDefault();
                        if (outSent == null)
                        {
                            outSent = new OutSent() { ID = trade.ID, ShopID = ShopID };
                            OutSentRepository.Add(outSent);
                        }
                        if (trade.Status == Constants.WAIT_SELLER_SEND_GOODS)
                        {
                            outSent.Message = Delivery_WaitSend;
                            outSent.Success = 0x00;
                        }
                        else
                        {
                            outSent.Message = Delivery_Success;
                            outSent.Success = 0x01; 
                            Console.WriteLine("更新一个已发货信息,订单ID：{0}", trade.TaobaoTID);
                        }
                        outSent.ID = trade.ID;
                        outSent.ShopID = ShopID;
                        OutSentRepository.Update(outSent);
                    }
                    OutputWriter.WriteLine(string.Format("获得详细信息订单ID：{0}", trade.TaobaoTID));

                    result = TradeRepository.Update(trade) > 0;
                    OutputWriter.WriteLine(string.Format("保存订单{0}信息成功 -- 第{1}条", trade.TaobaoTID, index));

                    //scope.Complete();
                }
            }
            catch (Exception e)
            {
                HandleException(string.Format("保存订单信息{0}失败 -- 第{1}条", trade.TaobaoTID, index), e);
                result = false;
            }
            return result;

        }

        private void UpdateTradesInfoAll()
        {
            try
            {
                var allStatus = GetUpdateTradeStatus().Select(s => s[0]).ToArray();
                //var statusInfo = status[0];
                var endTime = DateTime.Parse("1990.01.01");
                var allTradesNeedToBeUpdated = TradeRepository.FindAll().AsQueryable()
                                                              .Where(t => allStatus.Contains(t.Status)
                                                                       || (t.EndTime == null || t.EndTime.Value == endTime))
                                                              .Where(t => t.ShopID == ShopID)
                                                              .OrderByDescending(t => t.ID);

                var title = string.Format("订单详细信息");
                //var totalCount = allTradesNeedToBeUpdated.Count();
                //UpdateTask(title, totalCount, () =>
                //{
                //    return ProcessQueryable<Trade>(title, DefaultPageSize, (pageSize, pageNo) =>
                //    {
                //        return allTradesNeedToBeUpdated.Skip(pageSize * (pageNo - 1)).Take(pageSize).ToList();
                //    },
                //    UpdateTradeFullInfo, totalCount);
                //});

                UpdateTradesInternal(allTradesNeedToBeUpdated, title);
            }
            catch (Exception e)
            {
                HandleException(string.Format("获取需要更新的订单详细信息失败"), e);
            }
        }
        #endregion

        #region Get Trades

        private void GetTrades(bool usingIncrement)
        {
            if (usingIncrement)
                GetTradersIncrement();
            else
            {
                foreach (var status in GetUpdateTradeStatus())
                {
                  GetTradersNormal(status);
                }
            }
        }

        private void GetTradersNormal(string[] status)
        {
            try
            {
                var request = new TradesSoldGetRequest();
                request.PageSize = DefaultPageSize;
                request.StartCreated = DateTime.Now.AddDays(-ToolConfiguration.Current.UpdateBeforeDays);//new DateTime?(DateTime.Parse("1990.01.01"));
                request.EndCreated = new DateTime?(DateTime.Now);
                request.Fields = "num_iid,seller_nick, buyer_nick, title, type, created, sid, tid,  status, payment, discount_fee, adjust_fee, post_fee, total_fee, pay_time, buyer_memo, seller_memo, alipay_no, buyer_message,  iid, num, price, buyer_alipay_no, receiver_name, receiver_state, receiver_city, receiver_district, receiver_address, receiver_zip, receiver_mobile, receiver_phone, buyer_email, shipping_type, trade_memo, is_3D ,orders,promotion_details";//.title, orders.price,orders.oid, orders.num, orders.iid,  orders.status, orders.tid, orders.total_fee, orders.payment, orders.discount_fee, orders.adjust_fee, orders.timeout_action_time,orders.sku_properties_name, orders.item_meal_name, item_memo ";                                
                //request.Fields = "status, title, type, created, sid, tid,end_time, received_payment, alipay_no, iid, num, price, shipping_type,buyer_memo, seller_memo,";
                request.Status = status[0];// "WAIT_SELLER_SEND_GOODS";
                var firstPageList = Client.TradesSoldGet(request,SessionKey);

                var title = string.Format("{0}", status[1]);

                UpdateTask(title, firstPageList.TotalResults, () =>
                {
                    return ProcessPageList<Taobao.Top.Api.Domain.Trade>(title, request.PageSize.Value, firstPageList,
                     (pageNo) =>
                     {
                         request.PageNo = pageNo;
                         return Client.TradesSoldGet(request, SessionKey);
                     },
                     SaveNewTrade);
                });
            }
            catch (Exception e)
            {
                HandleException(string.Format("获取订单失败"), e);
            }

        }

        private bool SaveNewTrade(Taobao.Top.Api.Domain.Trade tTrade, long index)
        {
            if (tTrade.Type.Equals(FenXiaoType, StringComparison.OrdinalIgnoreCase))
            {
                OutputWriter.WriteLine(string.Format("订单{0}是分销订单!", tTrade.Tid));
                return false;
            }
            var result = false;
            try
            {
                if (TradeRepository.FindAll().AsQueryable().Where(r => r.TaobaoTID == tTrade.Tid).Count() <= 0)
                {
                    var trade = new Trade();
                    trade.AlipayNo = tTrade.AlipayNo;
                    trade.BuyerNick = tTrade.BuyerNick;
                    trade.BuyerMemo = "买家备注：" + tTrade.BuyerMemo + "||买家留言：" + tTrade.BuyerMessage;
                    trade.SellerMemo = tTrade.SellerMemo;
                    trade.OrderNum = (short)tTrade.Num;
                    trade.OrderPrice = tTrade.Payment;
                    trade.ShopID = ShopID;
                    trade.Status = tTrade.Status;
                    trade.SellerNick = tTrade.SellerNick;
                    trade.TaobaoTID = tTrade.Tid;
                    trade.Created = new DateTime?(DateTime.Parse(tTrade.Created));
                    if (tTrade.PayTime != null)
                    {
                        trade.PayTime = new DateTime?(DateTime.Parse(tTrade.PayTime));
                    }
                    else
                    {
                        trade.PayTime = new DateTime?(DateTime.Parse("1990.01.01"));
                    }
                    if (tTrade.EndTime != null)
                    {
                        trade.EndTime = new DateTime?(DateTime.Parse(tTrade.EndTime));
                    }
                    else
                    {
                        trade.EndTime = new DateTime?(DateTime.Parse("1990.01.01"));
                    }

                    // 新建一个 Trade的时候，不需要 判断 Process.
                    // 我们目前只有下载 WAIT_SELLER_SEND_GOODS，WAIT_BUYER_PAY，TRADE_NO_CREATE_PAY
                    // 这三种状态下的订单
                    if (tTrade.Status == "WAIT_SELLER_SEND_GOODS")
                    {
                        trade.TProcess = 0;
                    }
                    else if (tTrade.Status == "WAIT_BUYER_PAY")
                    {
                        trade.TProcess = -1;
                    }
                    else if (tTrade.Status == "TRADE_NO_CREATE_PAY")
                    {
                        trade.TProcess = -2;
                    }
                    else
                    {
                        trade.TProcess = 0;
                    }

                    result = TradeRepository.Add(trade) > 0;

                    if (tTrade.Orders.Count > 0)
                    {
                        trade.OrdersTitle = tTrade.Orders[0].Title;
                        trade.OrderNum = (short)tTrade.Orders.Count;
                        trade.DiscountFee = tTrade.Orders.Sum<Taobao.Top.Api.Domain.Order>(o => Util.ChangeType<decimal>(o.DiscountFee, 0));
                        trade.AdjustFee = tTrade.Orders.Sum<Taobao.Top.Api.Domain.Order>(o => Util.ChangeType<decimal>(o.AdjustFee, 0));
                        if (trade.OrderInfos == null || trade.OrderInfos.Count != tTrade.Orders.Count)
                        {
                            if (trade.OrderInfos != null && trade.OrderInfos.Count > 0)
                            {
                                var allOrderIDs = trade.OrderInfos.Where(c => c.TaobaoOID == null)
                                                                          .Select(c => c.ID).ToList();
                                foreach (var id in allOrderIDs)
                                {
                                    var order = trade.OrderInfos.FirstOrDefault(o => o.ID == id);
                                    if (order != null)
                                    {
                                        OrderInfoRepository.Delete(order);
                                    }
                                }
                            }
                            foreach (Taobao.Top.Api.Domain.Order tOrder in tTrade.Orders)
                            {
                                var order = OrderInfoRepository.FindAll().AsQueryable().Where(o => o.ShopID == ShopID
                                                                                                && o.TradeID == trade.ID
                                                                                                && o.TaobaoOID == tOrder.Oid)
                                                                                       .SingleOrDefault() ?? new OrderInfo();
                                order.NumIID = tOrder.NumIid;
                                order.Title = tOrder.Title;
                                order.TradeID = trade.ID;
                                order.Number = tOrder.Num;
                                order.Price = tOrder.Price;
                                order.IID = tOrder.Iid;
                                order.ItemMealName = tOrder.ItemMealName;
                                order.TaobaoOID = tOrder.Oid;

                                order.AdjustFee = Util.ChangeType<decimal>(tOrder.AdjustFee, 0);
                                order.DiscountFee = Util.ChangeType<decimal>(tOrder.DiscountFee, 0);
                                order.Payment = Util.ChangeType<decimal>(tOrder.Payment, 0);
                                order.RefundID = tOrder.RefundId;
                                if (tOrder.Status != null)
                                {
                                    order.Status = tOrder.Status;
                                }
                                if (tOrder.Modified != null)
                                {
                                    order.Modified = Util.ChangeType<DateTime>(tOrder.Modified, DateTime.MinValue);
                                }
                                //oi.Save();
                                //Item item = GetItemInfo(oi);
                                //oi.SkuPropertiesName = o.SkuPropertiesName;
                                //oi.OuterIId = item.OuterId;
                                //oi.NumIid = item.NumIid;
                                //oi.SkuID = o.SkuId;
                                order.SkuPropertiesName = tOrder.SkuPropertiesName;
                                order.OuterIID = string.IsNullOrEmpty(tOrder.OuterSkuId) ? tOrder.OuterIid : tOrder.OuterSkuId;
                                order.NumIID = tOrder.NumIid;
                                order.SkuID = tOrder.SkuId;
                                order.ShopID = ShopID;
                                OrderInfoRepository.AddOrUpdate(order);
                            }
                        }
                    }

                    if (tTrade.PromotionDetails.Count > 0)
                    {
                        if (trade.PromotionDetails == null || trade.PromotionDetails.Count != tTrade.PromotionDetails.Count )
                        {
                            foreach (var tDetail in tTrade.PromotionDetails)
                            {
                                var detail = PromotionDetailRepository.FindAll().AsQueryable().Where(p => p.TradeID == trade.ID
                                                                                                       && p.ShopID == ShopID
                                                                                                       && p.PromotionDetailID == tDetail.Id).SingleOrDefault() ?? new PromotionDetail();
                                detail.DiscountFee = Util.ChangeType<decimal>(tDetail.DiscountFee, 0);
                                detail.PromotionDetailID = tDetail.Id;
                                detail.Name = tDetail.PromotionName;
                                detail.ShopID = ShopID;
                                detail.TradeID = trade.ID;
                                PromotionDetailRepository.AddOrUpdate(detail);
                            }
                        }
                    }

                    TradeRepository.Update(trade);

                    OutputWriter.WriteLine(string.Format("获得新的订单：{0}-- 第{1}条", tTrade.Tid, index));
                }
                else
                {
                    OutputWriter.WriteLine(string.Format("已经存在订单：{0}-- 第{1}条", tTrade.Tid, index));
                }

                if (ToolConfiguration.Current.UpdateWhenGet)
                {
                    var savedTrade = TradeRepository.FindAll().AsQueryable().Where(r => r.TaobaoTID == tTrade.Tid).SingleOrDefault();
                    if (savedTrade != null)
                    {
                        UpdateTradeFullInfo(savedTrade, index);
                    }
                }
                //else
                //{
                //    result = false;
                //}                
            }
            catch (Exception e)
            {
                HandleException(string.Format("保存订单信息{0}失败 at:{1}", tTrade.Tid, DateTime.Now), e);
                result = false;
            }
            return result;
        }

        private void GetTradersIncrement()
        {
            try
            {
                var beforeDay = 0;
                var toUpdateBeforeDays = Shop.LastUpdateTradesTimeByIncreasement == null ? ToolConfiguration.Current.UpdateBeforeDays
                                                                                          : DateTime.Today.Subtract(Shop.LastUpdateTradesTimeByIncreasement.Value).Days;
                toUpdateBeforeDays = toUpdateBeforeDays <= 0 ? 0 : toUpdateBeforeDays;

                for (beforeDay = 0; beforeDay <= toUpdateBeforeDays; beforeDay++)
                {
                    var request = new IncrementTradesGetRequest();
                    request.PageSize = DefaultPageSize;

                    if (Shop.LastUpdateTradesTimeByIncreasement != null && beforeDay == 0)
                    {
                        var beforeMinutesOfUpdateByIncreament = Shop.BeforeMinutesOfUpdateByIncreament == null || Shop.BeforeMinutesOfUpdateByIncreament.Value <= 0
                                                                        ? DefaultBeforeMinutesOfUpdateByIncreament
                                                                        : Shop.BeforeMinutesOfUpdateByIncreament.Value;
                        beforeMinutesOfUpdateByIncreament = beforeMinutesOfUpdateByIncreament <= 0 ? 10 : beforeMinutesOfUpdateByIncreament;
                        request.StartModified = Shop.LastUpdateTradesTimeByIncreasement.Value.AddMinutes(-beforeMinutesOfUpdateByIncreament);
                        request.EndModified = DateTime.Now;
                    }
                    else
                    {
                        request.StartModified = DateTime.Today.AddDays(-beforeDay);
                        request.EndModified = DateTime.Today.AddDays(-beforeDay + 1).AddSeconds(-1);
                    }

                    if (beforeDay == 0)
                    {
                        request.EndModified = DateTime.Now;
                        try
                        {
                            var shop = ShopRepository.FindByID(ShopID);
                            shop.LastUpdateTradesTimeByIncreasement = request.EndModified;
                            ShopRepository.Update(shop);
                        }
                        catch (Exception e)
                        {
                            HandleException("Update LastUpdateTradesTimeByIncreasement Failed!", e);
                        }
                    }

                    //request.Status = status[0];
                    request.Nick = ShopName;
                    var firstTrades = Client.IncrementTradesGet(request, SessionKey);
                    var title = string.Format("增量的订单信息");
                    UpdateTaskIncrement(title, request.StartModified.Value, firstTrades.TotalResults, () =>
                    {
                        return ProcessPageList<Taobao.Top.Api.Domain.NotifyTrade>(title, request.PageSize.Value, firstTrades,
                         (pageNo) =>
                         {
                             request.PageNo = pageNo;
                             return Client.IncrementTradesGet(request, SessionKey);
                         },
                         SaveNewTradeIncrement);
                    });
                }
            }
            catch (Exception e)
            {
                HandleException(string.Format("获取增量订单失败"), e);
            }
        }
        private bool SaveNewTradeIncrement(Taobao.Top.Api.Domain.NotifyTrade nTrade,long index)
        {
            var result = false;
            if (nTrade.Type.Equals(FenXiaoType, StringComparison.OrdinalIgnoreCase))
            {
                OutputWriter.WriteLine(string.Format("订单{0}是分销订单!", nTrade.Tid));
                return false;
            }
            try
            {
                var trade = TradeRepository.FindAll().AsQueryable().Where(r => r.TaobaoTID == nTrade.Tid).SingleOrDefault();
                if (trade == null || ToolConfiguration.Current.UpdateWhenGet)
                {
                    var request = new TradeFullinfoGetRequest();
                    request.Fields = "num_iid,seller_nick, buyer_nick, title, type, created, sid, tid,  status, payment, discount_fee, adjust_fee, post_fee, total_fee, pay_time, buyer_memo, seller_memo, alipay_no, buyer_message,  iid, num, price, buyer_alipay_no, receiver_name, receiver_state, receiver_city, receiver_district, receiver_address, receiver_zip, receiver_mobile, receiver_phone, buyer_email, shipping_type, trade_memo, is_3D ,orders,promotion_details";//.title, orders.price,orders.oid, orders.num, orders.iid,  orders.status, orders.tid, orders.total_fee, orders.payment, orders.discount_fee, orders.adjust_fee, orders.timeout_action_time,orders.sku_properties_name, orders.item_meal_name, item_memo ";                                
                    request.Tid = nTrade.Tid;
                    var tTrade = Client.TradeFullinfoGet(request, SessionKey);
                    result = SaveNewTrade(tTrade, index);
                    OutputWriter.WriteLine(string.Format("获取增量的订单信息{0}成功 -- 第{1}条", nTrade.Tid, index));
                }
                else
                {
                    OutputWriter.WriteLine(string.Format("增量的订单信息{0}已经存在 -- 第{1}条", nTrade.Tid, index));
                }
            }
            catch (Exception e)
            {
                HandleException(string.Format("获取增量的订单信息{0}失败 -- 第{1}条", nTrade.Tid, index), e);
                result = false;
            }
            return result;
        }

        #endregion

        #region Get Refunds

        private void GetRefunds(bool usingIncreasement)
        {
            if (usingIncreasement)
                GetRefundsIncrement();
            else
                GetRefundsNormal();
        }
        private void GetRefundsNormal()
        {
            try
            {
                var request = new RefundsReceiveGetRequest();
                request.PageSize = DefaultPageSize;
                request.Fields = "refund_id, tid, title, buyer_nick, seller_nick, total_fee, status, created, refund_fee, oid, good_status, company_name, sid, payment, reason, desc, has_good_return, modified, order_status ";
                request.StartModified = DateTime.Now.AddDays(-ToolConfiguration.Current.UpdateBeforeDays);
                //request.Type = "fenxiao";  
                var firstRefunds = Client.RefundsReceiveGet(request, SessionKey);

                var title = "退款信息";
                UpdateTask(title, firstRefunds.TotalResults, () =>
                {
                    return ProcessPageList<Taobao.Top.Api.Domain.Refund>(title, request.PageSize.Value, firstRefunds,
                     (pageNo) =>
                     {
                         request.PageNo = pageNo;
                         return Client.RefundsReceiveGet(request, SessionKey);
                     },
                     SaveRefund);
                });
            }
            catch (Exception e)
            {
                HandleException(string.Format("更新退款失败"), e);
            }
        }
        private void GetRefundsIncrement()
        {
            try
            {
                var beforeDay = 0;
                var toUpdateBeforeDays = Shop.LastUpdateRefundsTimeByIncreasement == null ? ToolConfiguration.Current.UpdateBeforeDays
                                                                                          : DateTime.Today.Subtract(Shop.LastUpdateRefundsTimeByIncreasement.Value).Days;
                toUpdateBeforeDays = toUpdateBeforeDays <= 0 ? 0 : toUpdateBeforeDays;

                for (beforeDay = 0; beforeDay <= toUpdateBeforeDays; beforeDay++)
                {
                    var request = new IncrementRefundsGetRequest();
                    request.PageSize = DefaultPageSize;

                    if (Shop.LastUpdateRefundsTimeByIncreasement != null && beforeDay==0)
                    {
                        var beforeMinutesOfUpdateByIncreament = Shop.BeforeMinutesOfUpdateByIncreament==null || Shop.BeforeMinutesOfUpdateByIncreament.Value<=0
                                                                        ?DefaultBeforeMinutesOfUpdateByIncreament
                                                                        :Shop.BeforeMinutesOfUpdateByIncreament.Value;
                        beforeMinutesOfUpdateByIncreament = beforeMinutesOfUpdateByIncreament <= 0 ? 10 : beforeMinutesOfUpdateByIncreament;
                        request.StartModified = Shop.LastUpdateRefundsTimeByIncreasement.Value.AddMinutes(-beforeMinutesOfUpdateByIncreament);
                        request.EndModified = DateTime.Now;
                    }
                    else
                    {
                        request.StartModified = DateTime.Today.AddDays(-beforeDay);
                        request.EndModified = DateTime.Today.AddDays(-beforeDay + 1).AddSeconds(-1);
                    }

                    if (beforeDay == 0)
                    {
                        request.EndModified = DateTime.Now;
                        try
                        {
                            var shop = ShopRepository.FindByID(ShopID);
                            shop.LastUpdateRefundsTimeByIncreasement = request.EndModified;
                            ShopRepository.Update(shop);
                        }
                        catch (Exception e)
                        {
                            HandleException("Update LastUpdateRefundsTimeByIncreasement Failed!", e);
                        } 
                    }

                    request.Nick = ShopName;
                    var firstRefunds = Client.IncrementRefundsGet(request, SessionKey);
                    var title = "退款信息";
                    UpdateTaskIncrement(title, request.StartModified.Value, firstRefunds.TotalResults, () =>
                    {
                        return ProcessPageList<Taobao.Top.Api.Domain.NotifyRefund>(title, request.PageSize.Value, firstRefunds,
                         (pageNo) =>
                         {
                             request.PageNo = pageNo;
                             return Client.IncrementRefundsGet(request, SessionKey);
                         },
                         SaveRefundIncrement);
                    });
                }
            }
            catch (Exception e)
            {
                HandleException(string.Format("更新增量退款失败"), e);
            }
        }
        private bool SaveRefund(Taobao.Top.Api.Domain.Refund tRefund,long index)
        {
            var result = false;
            try
            {
                var refund = RefundRepository.FindAll().AsQueryable().Where(r => r.RefundID == tRefund.RefundId).SingleOrDefault();
                if (refund == null)
                {
                    refund = new Refund();
                    refund.Created = Util.ChangeType<DateTime>(tRefund.Created, DateTime.MinValue);
                    refund.Modified = Util.ChangeType<DateTime>(tRefund.Modified, DateTime.MinValue);
                    refund.Status = tRefund.Status;
                    refund.TradeID = tRefund.Tid;
                    refund.RefundID = tRefund.RefundId;
                    refund.Title = tRefund.Title;
                    refund.ItemNumID = tRefund.NumIid;
                    refund.RefundFee = Util.ChangeType<decimal>(tRefund.RefundFee, 0);
                    refund.TotalFee = Util.ChangeType<decimal>(tRefund.TotalFee, 0);
                    refund.ShopID = ShopID;
                    result = RefundRepository.AddOrUpdate(refund) > 0;

                    OutputWriter.WriteLine(string.Format("获得退款单号：{0} -- 第{1}条", tRefund.RefundId, index));
                }
                else
                {
                    if (tRefund.Modified != null)
                    {
                        refund.Modified = Util.ChangeType<DateTime>(tRefund.Modified, DateTime.MinValue);
                    }
                    refund.Status = tRefund.Status;
                    if (tRefund.RefundFee != null)
                    {
                        refund.RefundFee = Util.ChangeType<decimal>(tRefund.RefundFee, 0);
                    }
                    if (tRefund.TotalFee != null)
                    {
                        refund.TotalFee = Util.ChangeType<decimal>(tRefund.TotalFee, 0);
                    }
                    result = RefundRepository.Update(refund) > 0;
                    OutputWriter.WriteLine(string.Format("更新退款单号：{0} -- 第{1}条", tRefund.RefundId, index)); 
                }
                if (string.IsNullOrEmpty(refund.OuterID))
                {
                    SaveRefundOtherInfo(tRefund);
                }
            }
            catch (Exception e)
            {
                HandleException(string.Format("保存退款信息{0}失败 -- 第{1}条", tRefund.RefundId, index), e);
                result = false;
            }
            return result;
        }

        private void SaveRefundOtherInfo(Taobao.Top.Api.Domain.Refund tRefund)
        {
            try
            { 
                var refund = RefundRepository.Find(r=>r.RefundID ==tRefund.RefundId).SingleOrDefault();
                if(refund!=null)
                {
                    try
                    {
                        var request = new TradeFullinfoGetRequest();
                        request.Fields = "num_iid,sid,tid,status";
                        request.Tid = refund.TradeID;
                        var tTrade = Client.TradeFullinfoGet(request);
                        if (tTrade != null && (tTrade.NumIid > 0 || tRefund.NumIid > 0))
                        {
                            refund.ItemNumID = tTrade.NumIid > 0 ? tTrade.NumIid : tRefund.NumIid;

                            try
                            {
                                var itemGetRequest = new ItemGetRequest();
                                itemGetRequest.NumIid = refund.ItemNumID;
                                itemGetRequest.Fields = "num_iid,outer_id";
                                Top.Api.Domain.Item item = Client.ItemGet(itemGetRequest);
                                if (item != null)
                                {
                                    refund.OuterID = item.OuterId;

                                    RefundRepository.Update(refund);
                                    OutputWriter.WriteLine(string.Format("更新退款单号：{0} 的ItemNumID 和 OuterID信息", refund.RefundID)); 
                                }
                            }
                            catch (Exception ex)
                            {
                                OutputWriter.WriteLine(string.Format("更新退款单号：{0} 的ItemNumID 和 OuterID信息失败", refund.RefundID));                                 
                            }

                        }
                    }
                    catch
                    {
                    }

                }
            }
            catch
            {
            }
        }

        private bool SaveRefundIncrement(Taobao.Top.Api.Domain.NotifyRefund nTrade, long index)
        {
            var result = false;
            try
            {
                var request = new RefundGetRequest();
                request.RefundId = nTrade.Rid;
                request.Fields = "refund_id, tid, title, buyer_nick, seller_nick, total_fee, status, created, refund_fee, oid, good_status, company_name, sid, payment, reason, desc, has_good_return, modified, order_status ";
                var tRefund = Client.RefundGet(request, SessionKey);
                if (tRefund == null)
                {
                    OutputWriter.WriteLine(string.Format("获得退款单号：{0} 失败-- 第{1}条", nTrade.Rid,index), OutputFormatType.Failed);
                    return false;
                }
                else
                {
                    return SaveRefund(tRefund,index);
                }
            }
            catch (Exception e)
            {
                HandleException(string.Format("保存退款信息{0}失败 -- 第{1}条 ", nTrade.Rid,index), e);
                result = false;
            }
            return result;
        }
        #endregion

        #region Sent

        protected void SendDeliveries()
        {
            try
            {
                var allTradesInCurrentShop = TradeRepository.FindAll().AsQueryable().Where(t => t.ShopID == ShopID);
                var waitSendCount = OutSentRepository.FindAll().AsQueryable().Where(c => c.Success != 0x01
                                                                                 && c.Message == Delivery_WaitSend
                                                                                 && allTradesInCurrentShop.Any(t => t.ID == c.ID)).Count();
                OutputWriter.WriteLine(string.Format("待发货订单数：{0}", waitSendCount), OutputFormatType.Title);

                var waitSyncCount = OutSentRepository.FindAll().AsQueryable().Where(c => c.Success != 0x01 
                                                                                 && c.Message == Delivery_WaitSend
                                                                                 && c.OutSId != null
                                                                                 && allTradesInCurrentShop.Any(t => t.ID == c.ID)).Count();
                OutputWriter.WriteLine(string.Format("待同步订单数：{0}", waitSyncCount), OutputFormatType.Title);

                var waitSendOutSents = OutSentRepository.FindAll().AsQueryable().Where(c => c.Success != 0x01
                                                                                         && c.Message == Delivery_WaitSend
                                                                                         && c.OutSId != null
                                                                                         && c.CompanyCode != null
                                                                                         && c.Failure == null
                                                                                         && c.OrderType != Constants.OrderType_Virtual_Goods
                                                                                         && allTradesInCurrentShop.Any(t => t.ID == c.ID))
                                                                                 .ToList();
                OutputWriter.WriteLine(string.Format("待发货的非虚拟商品订单数：{0}", waitSendOutSents.Count()));
                var succeed = 0;
                foreach (OutSent os in waitSendOutSents)
                {
                    try
                    {
                        var trade = TradeRepository.FindAll().AsQueryable().Where(t => t.ID == os.ID ).Single();
                        if (SellerSentTrade(trade))
                            succeed++;
                    }
                    catch (Exception e)
                    {
                        HandleException(string.Format("非虚拟商品订单发货失败:{0}", os.ID), e);
                        Thread.Sleep(200);
                    }
                }
                OutputWriter.WriteLine(string.Format("待发货的非虚拟商品订单数总数:{0},成功:{1}", waitSendOutSents.Count(), succeed));


                var waitSendVGOutSents = OutSentRepository.FindAll().AsQueryable().Where(c => c.Success != 0x01
                                                                                         && c.Message == Delivery_WaitSend
                                                                                         && c.OrderType == Constants.OrderType_Virtual_Goods
                                                                                         && allTradesInCurrentShop.Any(t => t.ID == c.ID))
                                                                                  .ToList();

                succeed = 0;
                OutputWriter.WriteLine(string.Format("待发货的虚拟商品订单数：{0}", waitSendVGOutSents.Count()));
                foreach (OutSent os in waitSendVGOutSents)
                {
                    try
                    {
                        var trade = TradeRepository.FindAll().AsQueryable().Where(t => t.ID == os.ID ).Single();
                        if (SellerSentTrade(trade))
                            succeed++;
                    }
                    catch (Exception e)
                    {
                        HandleException(string.Format("虚拟商品订单发货失败:{0}", os.ID), e);
                        Thread.Sleep(200);
                    }
                }
                OutputWriter.WriteLine(string.Format("待发货的虚拟商品订单数总数:{0},成功:{1}", waitSendVGOutSents.Count(), succeed));
            }
            catch (Exception e)
            {
                HandleException(string.Format("发货失败"), e);
            }
        }

        private bool SellerSentTrade(Trade trade)
        {
            try
            {
                var outSent = OutSentRepository.FindAll().AsQueryable().Where(s => s.ID == trade.ID && trade.ShopID == ShopID).SingleOrDefault();
                if (outSent == null)
                {
                    OutputWriter.WriteLine(string.Format("发货失败，没有找到订单{0}的发货信息！", trade.TaobaoTID));
                    return false;
                }

                var tradeRequest = new TradeGetRequest();
                tradeRequest.Fields = "num_iid,seller_nick, buyer_nick, title, type, created, sid, tid,  status, payment, discount_fee, adjust_fee, post_fee, total_fee, pay_time, buyer_memo, seller_memo, alipay_no, buyer_message,  iid, num, price, buyer_alipay_no, receiver_name, receiver_state, receiver_city, receiver_district, receiver_address, receiver_zip, receiver_mobile, receiver_phone, buyer_email, shipping_type, trade_memo, is_3D ,orders,promotion_details";//.title, orders.price,orders.oid, orders.num, orders.iid,  orders.status, orders.tid, orders.total_fee, orders.payment, orders.discount_fee, orders.adjust_fee, orders.timeout_action_time,orders.sku_properties_name, orders.item_meal_name, item_memo ";                                
                tradeRequest.Tid = trade.TaobaoTID;
                var tTrade = Client.TradeGet(tradeRequest, SessionKey);
                if (tTrade.Status != Constants.WAIT_SELLER_SEND_GOODS)
                {
                    OutputWriter.WriteLine(string.Format("订单{0}已经在其他地方发货！", trade.TaobaoTID));
                    outSent.Success = 0x01;
                    outSent.Failure = "已经在其他地方发货";
                    outSent.Message = Delivery_Success;
                    outSent.ShopID = ShopID;
                    OutSentRepository.Update(outSent);
                    return true;
                }
                
                var sender = SenderRepository.FindAll().Where(s => s.ID == trade.ShopID).SingleOrDefault();
                if (sender != null)
                {
                    //using (var scope = new TransactionScope())
                    {
                        var request = new DeliverySendRequest();
                        request.Tid = trade.TaobaoTID;
                        if (outSent.OrderType != Constants.OrderType_Virtual_Goods)
                        {
                            if (outSent.CompanyCode == null)
                            {
                                request.CompanyCode = sender.CompanyCode;
                            }
                            else
                            {
                                request.CompanyCode = outSent.CompanyCode;
                            }
                            request.Memo = outSent.Memo;
                            request.OutSid = outSent.OutSId;
                            request.SellerAddress = sender.Address;
                            request.SellerAreaId = sender.AreaID;
                            request.SellerMobile = sender.Mobile;
                            request.SellerName = sender.Name;
                            request.SellerZip = sender.Zip;
                            request.SellerPhone = sender.Phone;
                        }
                        else
                        {
                            request.OrderType = outSent.OrderType;
                        }
                        try
                        {
                            if (Client.DeliverySend(request, SessionKey).IsSuccess)
                            {
                                outSent.Message = Delivery_Success;
                                outSent.Success = 0x01;
                                trade.Status = Constants.WAIT_BUYER_CONFIRM_GOODS;
                                OutputWriter.WriteLine(string.Format("订单{0}发货成功！", trade.TaobaoTID));
                            }
                            else
                            {
                                outSent.Message = Delivery_WaitSend;
                                outSent.Failure = "发货失败";
                                outSent.Success = 0x00;
                            }
                        }
                        catch (Exception exp)
                        {
                            outSent.Success = 0x00;
                            outSent.Failure = exp.ToString();
                        }
                        outSent.ShopID = ShopID;
                        OutSentRepository.Update(outSent);
                        TradeRepository.Update(trade);
                        //scope.Complete();
                    }
                
                return true;
                    }
            }
            catch(Exception e)
            {
                HandleException(string.Format("订单{0}发货失败！", trade.TaobaoTID),e);
                //OutputWriter.WriteLine(string.Format("订单{0}发货失败！", trade.TaobaoTID));
            }
            return false;
        }
        #endregion

        #region Preparing Operation
        private void PrepareDelivery()
        {
            try
            {
                OutputWriter.WriteLine(string.Format("正在同步订单物流信息。"), OutputFormatType.Title);
                using (var infoContext = new InfoGaDbContext())
                {
                    var salePayRepository = new EntityRepository<SalePay, long>(infoContext);
                    var expressCompanyRepository = new EntityRepository<ExpressCompany, int>(infoContext);
                    var allExpressCompanies = expressCompanyRepository.FindAll().AsQueryable().ToList();
                    var allOutSents = OutSentRepository.FindAll().AsQueryable()
                                                                 .Where(s => s.Success != 0x01
                                                                           && s.Message.Equals(Delivery_WaitSend, StringComparison.OrdinalIgnoreCase)
                                                                           && (s.ShopID == null || s.ShopID == ShopID));
                   var allOutSentIDs = allOutSents.Select(c => c.ID).OrderBy(c=>c);

                    var allStats = new byte?[] { 0x01, 0x02, 0x03 };
                    var defaultPageSize = 50;
                    //var allSalePays = salePayRepository.FindAll()
                    //                                .AsQueryable()
                    //                                .Where(s => s.TradeID != null
                    //                                         && allOutSentIDs.Contains(s.TradeID.Value)
                    //                                         && allStats.Contains(s.Stats))
                    //                                .Distinct()
                    //                                .OrderBy(s=>s.ID);

                    var totalCount = allOutSents.Count();
                    var totalPageCount = totalCount == 0 ? 0 : (totalCount / defaultPageSize + (totalCount % defaultPageSize > 0 ? 1 : 0));

                    OutputWriter.WriteLine(string.Format("一共有{0}条订单的物流信息需要同步", totalCount), OutputFormatType.Title);
                    //OutputWriter.WriteLine(string.Format("一共找到{0}条订单的物流信息可以同步", totalCount), OutputFormatType.Title);

                    for (var i = 0; i < totalPageCount; i++)
                    {
                        var outSentIDs = allOutSentIDs.Skip(i * defaultPageSize)
                                                    .Take(defaultPageSize)
                                                    .ToArray();
                        var salePays = salePayRepository.FindAll()
                                                    .AsQueryable()
                                                    .Where(s => s.TradeID != null
                                                             && outSentIDs.Contains(s.TradeID.Value)
                                                             && allStats.Contains(s.Stats))
                                                    .Distinct()
                                                    .ToList();
                       //var salePays = salePayRepository.FindAll()
                       //                            .AsQueryable()
                       //                            .Where(s => s.TradeID != null
                       //                                     && allOutSentIDs.Contains(s.TradeID.Value)
                       //                                     && allStats.Contains(s.Stats))
                       //                            .Distinct()
                       //                            .ToList();


                       UpdateTask("同步订单物流信息", salePays.Count, () =>
                       {
                           var succeed = 0L;
                           foreach (var salePay in salePays)
                           {
                               try
                               {
                                   var outSent = allOutSents.Where(o => o.ID == salePay.TradeID).SingleOrDefault();
                                   if (outSent != null)
                                   {
                                       var expressCompany = allExpressCompanies.Where(e => e.ID.ToString() == salePay.ExpressCompanyID).SingleOrDefault();
                                       if (expressCompany == null)
                                       {
                                           //HandleException(string.Format("没有找到订单{0}的物流公司", outSent.ID), new Exception(string.Format("没有找到订单{0}的物流公司", outSent.ID)));
                                           // continue;
                                           outSent.Failure = "同步物流信息成功，但是物流公司为空";
                                       }
                                       else
                                       {
                                           outSent.CompanyCode = expressCompany.Code;
                                       }
                                       outSent.OutSId = salePay.ExpressNumber;
                                       outSent.OrderType = salePay.OrderType; 
                                       //Could Set ShopID here, can't determine current outsent is of current shop.
                                       if (OutSentRepository.Update(outSent) > 0)
                                           succeed++;
                                       OutputWriter.WriteLine(string.Format("同步订单{0}的物流信息成功", salePay.TradeID));
                                   }
                               }
                               catch (Exception e)
                               {
                                   HandleException(string.Format("同步订单{0}的物流信息失败", salePay.TradeID), e);
                               }
                           }
                           return succeed;
                       });               
                    }
                        
                    //OutputWriter.WriteLine(string.Format("一共找到{0}条订单的物流信息可以同步,成功同步{1}条", salePays.Count,succeed), OutputFormatType.Title);
                }
            }
            catch (Exception e)
            {
                HandleException(string.Format("物流准备失败"), e);
            }
        }
        #endregion

        #region Get Items
        private void GetItems()
        {
            try
            {
                var request = new ItemsOnsaleGetRequest();
                request.PageSize = DefaultPageSize;
                request.Fields = "approve_status,num_iid,title,nick,type,cid,pic_url,num,props,valid_thru,list_time,price,has_discount,has_invoice,has_warranty,has_showcase,modified,delist_time,postage_id,seller_cids,outer_id";
                request.StartModified = DateTime.Now.AddDays(-60);
                //request.Type = "fenxiao";  
                var firstItems = Client.ItemsOnsaleGet(request, SessionKey);

                var title = "商品信息";
                UpdateTask(title, firstItems.TotalResults, () =>
                {
                    return ProcessPageList<Taobao.Top.Api.Domain.Item>(title, request.PageSize.Value, firstItems,
                     (pageNo) =>
                     {
                         request.PageNo = pageNo;
                         return Client.ItemsOnsaleGet(request, SessionKey);
                     },
                     SaveItem);
                });
            }
            catch (Exception e)
            {
                HandleException(string.Format("更新商品信息失败"), e);
            }
        }

        private bool SaveItem(Taobao.Top.Api.Domain.Item tItem, long index)
        {
            var result = false; 
            try
            {
                //using (var scope = new TransactionScope())
                {
                    var item = ItemRepository.FindAll().AsQueryable().Where(r => r.NumIID != null
                                                                         && r.NumIID == tItem.NumIid
                                                                         && r.ShopID == ShopID)
                                                                     .SingleOrDefault()
                               ?? new Item();
                    var request = new ItemGetRequest();
                    request.NumIid = tItem.NumIid;
                    request.Fields = @"detail_url,num_iid,title,nick,type,props_name,created,promoted_service,is_lightning_consignment,is_fenxiao,auction_point,property_alias,volume,template_id,after_sale_id,is_xinpin,sub_stock,cid,seller_cids,props,input_pids,input_str,pic_url,num,valid_thru,list_time,delist_time,stuff_status,price,post_fee,express_fee,ems_fee,has_discount,freight_payer,has_invoice,has_warranty,has_showcase,modified,increment,approve_status,postage_id,product_id,outer_id,is_virtual,is_taobao,is_ex,is_timing,is_3D,score,one_station,second_kill,auto_fill,violation,is_prepay,ww_status,wap_desc,wap_detail_url,cod_postage_id,sell_promise";
                    var detailItem = Client.ItemGet(request);
                    if (detailItem.Created != null)
                    {
                        item.Created = Util.ChangeType<DateTime>(detailItem.Created, DateTime.MinValue);
                    }
                    if (detailItem.DelistTime != null)
                    {
                        item.DelistTime = Util.ChangeType<DateTime>(detailItem.DelistTime, DateTime.MinValue);
                    }
                    if (detailItem.ListTime != null)
                    {
                        item.ListTime = Util.ChangeType<DateTime>(detailItem.ListTime, DateTime.MinValue);
                    }
                    if (detailItem.Modified != null)
                    {
                        item.Modified = Util.ChangeType<DateTime>(detailItem.Modified, DateTime.MinValue);
                    }
                    //item.Desc = detailItem.Desc;
                    item.DetailUrl = detailItem.DetailUrl;
                    item.EmsFee = Util.ChangeType<Decimal>(detailItem.EmsFee, 0);
                    item.ExpressFee = Util.ChangeType<Decimal>(detailItem.ExpressFee, 0);
                    item.HasDiscount = detailItem.HasDiscount;
                    item.HasShowCase = detailItem.HasShowcase;
                    item.HasWarranty = detailItem.HasWarranty;
                    item.Nick = detailItem.Nick;
                    item.Num = detailItem.Num;
                    item.NumIID = detailItem.NumIid;
                    item.PicUrl = detailItem.PicUrl;
                    item.PostFee = Util.ChangeType<Decimal>(detailItem.PostFee, 0);
                    item.Price = Util.ChangeType<Decimal>(detailItem.Price, 0);
                    item.PromotedService = detailItem.PromotedService;
                    item.PropsName = detailItem.PropsName;
                    item.ShopID = ShopID;
                    item.Title = detailItem.Title;
                    item.Type = detailItem.Type;
                    item.ValidThru = detailItem.ValidThru;
                    item.OuterID = detailItem.OuterId;
                    var dd = ItemRepository.AddOrUpdate(item);
                    result = dd > 0;
                    OutputWriter.WriteLine(string.Format("保存商品信息{0}成功 -- 第{1}条", tItem.NumIid, index));
                    //scope.Complete();
                }

            }
            catch (Exception e)
            {
                HandleException(string.Format("保存商品信息{0}失败 -- 第{1}条", tItem.NumIid, index), e);
                result = false;
            }
            return result;
        }
        #endregion
        #endregion

        #region Helper Methods

        private List<string[]> GetUpdateTradeStatus()
        {
            var result = new List<string[]>();
            if (ToolConfiguration.Current.WaitBuyerPay)
                result.Add(new string[] { "WAIT_BUYER_PAY", "等待买家付款的订单" });
            if (ToolConfiguration.Current.TradeNoCreatePay)
                result.Add(new string[] { "TRADE_NO_CREATE_PAY", "等待支付宝创建付款的订单" });
            if (ToolConfiguration.Current.WaitSellerSendGoods)
                result.Add(new string[] { "WAIT_SELLER_SEND_GOODS", "等待卖家发货的订单" });
            return result;
        }
        #endregion
    }
}
